#ifndef _core_switch_switch_hpp_
#define _core_switch_switch_hpp_

/** \file switch.hpp
 *  \author Adrian Schweizer
 *  \created  $Mo 11 Feb 08:33:01 pm CET 2008 schwadri@SchwadriLaptop.local$
 *  \modified $Mo 11 Feb 08:33:01 pm CET 2008 schwadri@SchwadriLaptop.local$
 */

#include <boost/preprocessor/limits.hpp>

#ifndef CORE_SWITCH_LIMIT_CASES
    #define CORE_SWITCH_LIMIT_CASES 10
#endif

#if (CORE_LIMIT_SWITCH_MAX_CASES > BOOST_PP_LIMIT_REPEAT)
    #error CORE_LIMIT_SWITCH_MAX... exceeds Boost.Preprocessor limit
#endif
#if (CORE_LIMIT_SWITCH_MAX_CASES > BOOST_PP_LIMIT_ITERATION)
    #error CORE_LIMIT_SWITCH_MAX... exceeds Boost.Preprocessor limit
#endif

#include <boost/mpl/assert.hpp>
#include <boost/mpl/less_equal.hpp>

#include "detail/tag_of.hpp"
#include <boost/fusion/sequence/intrinsic/size.hpp>
#include "detail/size_impl.hpp"

#include "detail/switch_impl.hpp"

namespace core {

    template <typename RetVal, typename Key>
        struct switcher
        {
            switcher(Key key)
            :   m_key(key)
            { }

            template <typename Cases>
                RetVal operator[](const Cases& cases)
                {
                    return call(cases);
                }

            template <typename Cases>
                RetVal operator()(const Cases& cases)
                {
                    return call(cases);
                }

        private:
            template <typename Cases>
                RetVal  call(const Cases& cases)
                {
                    typedef typename boost::fusion::result_of::size<Cases>::type    count;
                    BOOST_MPL_ASSERT_MSG((boost::mpl::less_equal<count,boost::mpl::size_t<CORE_SWITCH_LIMIT_CASES> >::type::value),
                                            TOO_MANY_CASES_SUPPLIED_TO_switch_INCREASE_CORE_SWITCH_LIMIT_CASES, );

                    typedef typename detail::get_impl<count::value>::type    impl;
                    return impl::template eval<RetVal,Key,Cases>(m_key,cases);
                }


            Key m_key;
        };

    template <typename RetVal, typename Key>
        switcher<RetVal,Key> switch_(Key key)
        {
            return switcher<RetVal,Key>(key);
        }

} // namespace core

#endif // _core_switch_switch_hpp_
